#!/usr/bin/perl -w

use strict;

use Test::More tests => 7;

###############################################################################
# 1. use Proc:RPC.
###############################################################################
BEGIN { use_ok('Proc::RPC') };


###############################################################################
# 2. Simple test using RPC.
###############################################################################
{
  my $p = Proc::RPC->new();
  $p->rpc(sub { return { a => 1, b => 2, c => [ @_ ], d => 5 } }, 4, 7, 9);
  my $ret = $p->join();
  my $expected = bless( {
                 'stderr' => '',
                 'status' => '0',
                 'stdout' => '',
                 'result' => [
                                 {
                                   'c' => [
                                            4,
                                            7,
                                            9
                                          ],
                                   'a' => 1,
                                   'b' => 2,
                                   'd' => 5
                                 }
                               ]
               }, 'Proc::RPC::Result' );
  is($ret, $expected, "Simple test using RPC");
}


###############################################################################
# 3. Standard Output capture test.
###############################################################################
{
  my $stdout_test = "Standard Output capture test";
  my $p = Proc::RPC->new();
  $p->rpc(sub { print $stdout_test });
  my $ret = $p->join();
  is($ret->stdout(), $stdout_test, $stdout_test);
}

###############################################################################
# 4. Standard Error capture test.
###############################################################################
{
  my $stderr_test = "Standard Error capture test";
  my $p = Proc::RPC->new();
  $p->rpc(sub { print STDERR $stderr_test });
  my $ret = $p->join();
  is($ret->stderr(), $stderr_test, $stderr_test);
}


###############################################################################
# 5. Status Code capture test.
###############################################################################
{
  my $p = Proc::RPC->new();
  $p->rpc(sub { exit 1 });
  my $ret = $p->join();
  is($ret->status(), 256, "Status Code capture test");
}


###############################################################################
# 6. Parallel Pi Calculation.
###############################################################################
{
  my $pi_part = sub {
    my ($id, $N, $np) = @_;
    my $sum;

    foreach (grep { $_ % $np eq $id } (0 .. $N)) {
      my $x = ($_ + 0.5) / $N;
      $sum += 4 / (1 + $x * $x)
    }

    return $sum / $N;
  };

  my $N = 50000;
  my $np = 5;

  my @running;

  foreach (0..$np - 1) {
    my $p = Proc::RPC->new();
    $p->rpc($pi_part, $_, $N, $np);
    push(@running, $p);
  }

  my $sum;
  while (@running != 0) {
    my @alive;
    foreach (@running) {
      if ($_->poll()) {
        push(@alive, $_);
      } else {
        $sum += $_->join();
      }
    }
    @running = @alive;
  }
  is($sum, 3.14163265322313, "Parallel Pi Calculation");
}

###############################################################################
# 7. Dynamic routine generation.
###############################################################################
{
  my $pow_generator = sub {
    my $base = shift;
    return eval "sub { return $base ** shift; }"
  };

  my $p = Proc::RPC->new();
  $p->rpc($pow_generator, 2);
  my $binary_pow = shift @{$p->join()->result()};

  is(&$binary_pow(5), 32, "Dynamic routine generation");
}
